package bo.gustavo.scrapper.worker;

import java.io.IOException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.validator.routines.EmailValidator;
import org.apache.commons.validator.routines.UrlValidator;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import bo.gustavo.scrapper.model.AppData;
import bo.gustavo.scrapper.model.Persister;
import bo.gustavo.scrapper.util.DataBaseAccessType;

/**
 * Class that executes all the parsing logic and gets all the required
 * information
 * 
 * @author Gustavo Vera
 * */
public class Parser {

	private static String EMAIL_PARSER_DISCRIMINATOR = "mailto:";

	private static String URL_PARSER_DISCRIMINATOR = "http";

	private static final int MAX_RETRY = 10;

	private String url;

	private String appTitle;

	private String category;

	private boolean isPaid;

	private Document doc;

	public Parser(String url, String appTitle, String category, boolean isPaid) {
		this.url = url;
		this.appTitle = appTitle;
		this.category = category;
		this.isPaid = isPaid;
	}

	/**
	 * Initializes the document to be parsed using the URL provided in the
	 * constructor
	 * 
	 * @author Gustavo Vera
	 * */
	private void initDocument() {
		boolean docLoaded = false;
		int retries = 0;
		while (!docLoaded) {
			try {
				doc = Jsoup.connect(url).get();
				System.out.println("Connected to " + url);
				System.out.println("Title of page is : " + doc.title());
				docLoaded = true;
			} catch (IOException e) {
				System.out.println("Something wrong happened fetching the following url:  " + url);
				retries++;
				if (retries == MAX_RETRY) {
					docLoaded = true;
				}
				try {
					Thread.currentThread().sleep(5000);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
			}
		}
	}

	/**
	 * Starts fetching all the information
	 * 
	 * @author Gustavo Vera
	 * */
	public void beginFetch() {
		initDocument();
		if (doc != null) {
			AppData appData = new AppData();
			appData.setAppURL(url);
			appData.setCategory(category);
			appData.setTitle(appTitle);
			appData.setPaid(isPaid);
			fetchDeveloperName(appData);
			fetchDeveloperWebsiteAndEmail(appData);
			fetchReviewAmount(appData);
			Persister.getInstance().maskOperations(null, appData, DataBaseAccessType.SAVE);
		}
	}

	private void fetchDeveloperWebsiteAndEmail(AppData appData) {
		Element ele = doc.select("div.doc-overview").first();
		Elements contactInfoElements = ele.select("a.more-arrow-link");
		for (Element linkElement : contactInfoElements) {
			String link = linkElement.attr("abs:href");
			if (StringUtils.startsWith(link, EMAIL_PARSER_DISCRIMINATOR)) {
				String email = extractEmail(link);
				if (EmailValidator.getInstance().isValid(email)) {
					appData.setDeveloperEmail(email);
				}
			} else if (StringUtils.startsWith(link, URL_PARSER_DISCRIMINATOR) && UrlValidator.getInstance().isValid(link)) {
				appData.setDeveloperWebsite(extractURL(link));
			}
		}
	}

	private void fetchReviewAmount(AppData appData) {
		Element amountElement = doc.select("div#details-tab-2").first();
		String value = "";
		try {
			Element userRatingsElement = amountElement.select("div.votes").first();
			value = StringUtils.remove(userRatingsElement.text(), ",");
		} catch (Exception e) {
			value = "0";
		}

		appData.setReviewAmount(Integer.valueOf(value));
	}

	private String extractURL(String link) {
		return StringUtils.substringBetween(link, "q=", "&");
	}

	private String extractEmail(String link) {
		return StringUtils.substringAfter(link, EMAIL_PARSER_DISCRIMINATOR);
	}

	private void fetchDeveloperName(AppData appData) {
		Element ele = doc.select("td.doc-banner-title-container").first();
		Element name = ele.select("a.doc-header-link").first();
		appData.setDeveloperName(name.text());
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getUrl() {
		return url;
	}

}
